/* * Copyright (c) 2009-2012 jMonkeyEngine * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * * Neither the name of 'jMonkeyEngine' nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package com.jme3.input.android; import android.opengl.GLSurfaceView; import android.view.GestureDetector; import android.view.InputDevice; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.ScaleGestureDetector; import android.view.View; import com.jme3.input.JoyInput; import com.jme3.input.TouchInput; import com.jme3.system.AppSettings; import java.util.logging.Level; import java.util.logging.Logger; /** * <code>AndroidInput</code> is the main class that connects the Android system * inputs to jME. It receives the inputs from the Android View and passes them * to the appropriate classes based on the source of the input.</br> * This class is to be extended when new functionality is released in Android. * * @author iwgeric */ public class AndroidInputHandler implements View.OnTouchListener, View.OnKeyListener { private static final Logger logger = Logger.getLogger(AndroidInputHandler.class.getName()); protected GLSurfaceView view; protected AndroidTouchInput touchInput; protected AndroidJoyInput joyInput; public AndroidInputHandler() { touchInput = new AndroidTouchInput(this); joyInput = new AndroidJoyInput(this); } public void setView(View view) { if (this.view != null && view != null && this.view.equals(view)) { return; } if (this.view != null) { removeListeners(this.view); } this.view = (GLSurfaceView)view; if (this.view != null) { addListeners(this.view); } joyInput.setView((GLSurfaceView)view); } public View getView() { return view; } protected void removeListeners(GLSurfaceView view) { view.setOnTouchListener(null); view.setOnKeyListener(null); touchInput.setGestureDetector(null); touchInput.setScaleDetector(null); } protected void addListeners(GLSurfaceView view) { view.setOnTouchListener(this); view.setOnKeyListener(this); AndroidGestureProcessor gestureHandler = new AndroidGestureProcessor(touchInput); touchInput.setGestureDetector(new GestureDetector( view.getContext(), gestureHandler)); touchInput.setScaleDetector(new ScaleGestureDetector( view.getContext(), gestureHandler)); } public void loadSettings(AppSettings settings) { touchInput.loadSettings(settings); } public TouchInput getTouchInput() { return touchInput; } public JoyInput getJoyInput() { return joyInput; } /* * Android input events include the source from which the input came from. * We must look at the source of the input event to determine which type * of jME input it belongs to. * If the input is from a gamepad or joystick source, the event is sent * to the JoyInput class to convert the event into jME joystick events. * </br> * If the input is from a touchscreen source, the event is sent to the * TouchProcessor to convert the event into touch events. * The TouchProcessor also converts the events into Mouse and Key events * if AppSettings is set to simulate Mouse or Keyboard events. * * Android reports the source as a bitmask as shown below.</br> * * InputDevice Sources * 0000 0000 0000 0000 0000 0000 0000 0000 - 32 bit bitmask * * 0000 0000 0000 0000 0000 0000 1111 1111 - SOURCE_CLASS_MASK (0x000000ff) * 0000 0000 0000 0000 0000 0000 0000 0000 - SOURCE_CLASS_NONE (0x00000000) * 0000 0000 0000 0000 0000 0000 0000 0001 - SOURCE_CLASS_BUTTON (0x00000001) * 0000 0000 0000 0000 0000 0000 0000 0010 - SOURCE_CLASS_POINTER (0x00000002) * 0000 0000 0000 0000 0000 0000 0000 0100 - SOURCE_CLASS_TRACKBALL (0x00000004) * 0000 0000 0000 0000 0000 0000 0000 1000 - SOURCE_CLASS_POSITION (0x00000008) * 0000 0000 0000 0000 0000 0000 0001 0000 - SOURCE_CLASS_JOYSTICK (0x00000010) * * 1111 1111 1111 1111 1111 1111 0000 0000 - Source_Any (0xffffff00) * 0000 0000 0000 0000 0000 0000 0000 0000 - SOURCE_UNKNOWN (0x00000000) * 0000 0000 0000 0000 0000 0001 0000 0001 - SOURCE_KEYBOARD (0x00000101) * 0000 0000 0000 0000 0000 0010 0000 0001 - SOURCE_DPAD (0x00000201) * 0000 0000 0000 0000 0000 0100 0000 0001 - SOURCE_GAMEPAD (0x00000401) * 0000 0000 0000 0000 0001 0000 0000 0010 - SOURCE_TOUCHSCREEN (0x00001002) * 0000 0000 0000 0000 0010 0000 0000 0010 - SOURCE_MOUSE (0x00002002) * 0000 0000 0000 0000 0100 0000 0000 0010 - SOURCE_STYLUS (0x00004002) * 0000 0000 0000 0001 0000 0000 0000 0100 - SOURCE_TRACKBALL (0x00010004) * 0000 0000 0001 0000 0000 0000 0000 1000 - SOURCE_TOUCHPAD (0x00100008) * 0000 0000 0010 0000 0000 0000 0000 0000 - SOURCE_TOUCH_NAVIGATION (0x00200000) * 0000 0001 0000 0000 0000 0000 0001 0000 - SOURCE_JOYSTICK (0x01000010) * 0000 0010 0000 0000 0000 0000 0000 0001 - SOURCE_HDMI (0x02000001) * * Example values reported by Android for Source * 4,098 = 0x00001002 = * 0000 0000 0000 0000 0001 0000 0000 0010 - SOURCE_CLASS_POINTER * SOURCE_TOUCHSCREEN * 1,281 = 0x00000501 = * 0000 0000 0000 0000 0000 0101 0000 0001 - SOURCE_CLASS_BUTTON * SOURCE_KEYBOARD * SOURCE_GAMEPAD * 16,777,232 = 0x01000010 = * 0000 0001 0000 0000 0000 0000 0001 0000 - SOURCE_CLASS_JOYSTICK * SOURCE_JOYSTICK * * 16,778,513 = 0x01000511 = * 0000 0001 0000 0000 0000 0101 0001 0001 - SOURCE_CLASS_BUTTON * SOURCE_CLASS_JOYSTICK * SOURCE_GAMEPAD * SOURCE_KEYBOARD * SOURCE_JOYSTICK * * 257 = 0x00000101 = * 0000 0000 0000 0000 0000 0001 0000 0001 - SOURCE_CLASS_BUTTON * SOURCE_KEYBOARD * * * */ @Override public boolean onTouch(View view, MotionEvent event) { if (view != getView()) { return false; } boolean consumed = false; int source = event.getSource(); // logger.log(Level.INFO, "onTouch source: {0}", source); boolean isTouch = ((source & InputDevice.SOURCE_TOUCHSCREEN) == InputDevice.SOURCE_TOUCHSCREEN); // logger.log(Level.INFO, "onTouch source: {0}, isTouch: {1}", // new Object[]{source, isTouch}); if (isTouch && touchInput != null) { // send the event to the touch processor consumed = touchInput.onTouch(event); } return consumed; } @Override public boolean onKey(View view, int keyCode, KeyEvent event) { if (view != getView()) { return false; } boolean consumed = false; int source = event.getSource(); // logger.log(Level.INFO, "onKey source: {0}", source); boolean isTouch = ((source & InputDevice.SOURCE_TOUCHSCREEN) == InputDevice.SOURCE_TOUCHSCREEN) || ((source & InputDevice.SOURCE_KEYBOARD) == InputDevice.SOURCE_KEYBOARD); // logger.log(Level.INFO, "onKey source: {0}, isTouch: {1}", // new Object[]{source, isTouch}); if (touchInput != null) { consumed = touchInput.onKey(event); } return consumed; } }